#include "Filesystem.h"
#include "Logger.h"
#include "LuaUtils.h"
#include <fstream>
#include <iostream>

std::string Filesystem::getWorkingDirectory() 
{
    // Get current working directory
	char currentPath[FS_MAX_PATH_LENGTH];
    if ( !GetCurrentDir(currentPath, sizeof(currentPath)) )
    {
        LOG(logERROR) << "Failed to get working directory.";
        currentPath[0] = '\0';
    }

    return std::string(currentPath);
}

Filesystem::Filesystem()
{
    _localPath = ".";
}

Filesystem::Filesystem(std::string localPath)
{
    _localPath = getWorkingDirectory();
	setLocalPath( toAbsolutePath(localPath) );
}

std::string Filesystem::getTextResource(std::string resName)
{
	int bytesRead;
	char *buffer = (char *)getBinaryResource( resName, bytesRead );
	if(bytesRead > 0)
		return std::string( buffer, bytesRead );
	else
	{
		LOG(logERROR) << "Could not get text resource; does not exist.";
		return std::string("");
	}
}

// loads a binary resource with the specified name into the buffer dest
// returns a pointer to a buffer array (that must be freed by the caller!)
unsigned char *Filesystem::getBinaryResource(std::string resName, int &bytesRead)
{
	char *buffer;

	// Open the binary resource
	std::ifstream is;
	std::string realFileName = toAbsolutePath(resName);
	is.open( realFileName.c_str(), std::ios::binary );

	if(!is.is_open())
	{
		LOG(logERROR) << "Could not open file " << realFileName;
		bytesRead = -1;
		return NULL;
	}
	else
		LOG(logDEBUG) << "Opened " << realFileName;

	// Get length of file:
  	is.seekg( 0, std::ios::end );
	bytesRead = is.tellg();
	is.seekg( 0, std::ios::beg );

	// Allocate buffer (extra character for null termination)
	buffer = new char[bytesRead+1];

	// Read data as a block
	is.read( buffer, bytesRead );
	is.close();

	return (unsigned char *)buffer;
}

std::string Filesystem::formatFilename(std::string resName, std::string resType)
{
	std::string temp = resName;
	for(unsigned int i = 0; i < temp.length(); ++i)
	{
		if(temp[i] == '.')
			temp[i] = FS_PATH_SEPARATOR;
	}
	return (temp + "." + resType);
}

// negative values are errors
int Filesystem::loadLuaChunk(lua_State* L, std::string resName, std::string debugName)
{
	std::string fileName = formatFilename(resName, "lua");
	LOG(logDEBUG) << "FS loading chunk " << resName << " w/ parsed filename " << fileName << " as " << debugName;

	std::string chunk = getTextResource(fileName);
	int error = luaL_loadbuffer(L, chunk.c_str(), chunk.size(), debugName.c_str());
	if(error)
	{
		LOG(logERROR) << "Error loading chunk; probably a syntax error (see following message)";
		LOG(logERROR) << getSafeLuaString(L, -1);
		lua_pop(L, 1);
		return -1;
	}
	else
		return 0;
}

std::string Filesystem::toAbsolutePath(std::string path)
{
	std::string absolutePath;

	// Is this already an absolute directory?
    size_t firstColon = path.find_first_of( ':' );
    size_t firstSlash = path.find_first_of( FS_PATH_SEPARATOR );
    
    if ( (firstColon < firstSlash) || (firstSlash == 0) ) 
    {   
        // Specified path is already absolute
        return path;
    }
    else 
    {
		// Construct absolute path
        absolutePath += _localPath;
        absolutePath += FS_PATH_SEPARATOR;
        absolutePath += path;
    }

	return absolutePath;
}

std::string Filesystem::getLocalPath()
{
    return _localPath;
}

void Filesystem::setLocalPath(std::string path)
{
    _localPath = toAbsolutePath( path );
}

Filesystem::~Filesystem()
{
	// nothing to do
}
